package com.zfast.config.junit.game;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import com.zfast.forge.constant.SysConstant;
import com.zfast.forge.game.Game;
import com.zfast.forge.navigation.Coordinate;
import com.zfast.forge.pojo.bo.PlayerInstance;
import com.zfast.forge.pojo.dto.*;
import com.zfast.forge.qlExpress.FormulaEnum;
import com.zfast.forge.qlExpress.QLExpressUtil;
import com.zfast.forge.service.*;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;

/**
 * @author zgn
 * @Description: springBootTest
 * @date 2022/1/11 0011
 */
@SpringBootTest
class 羽毛球实战Spring {
    @Test
    public void egMin() {//e.g.
        System.out.println("X+\"+\"+Y+\"+\"+Z");
    }

    @Test
    public void egMax() {//e.g.
        //region 模拟数据
        System.out.println("--------------------Start--------------------");
        //endregion

        //region 数据处理
        System.out.println("--------------------Deal--------------------");
        //endregion

        //region 数据展示
        System.out.println("--------------------Done--------------------");
        //endregion
    }

    @Resource
    FieldLayerService fieldLayerService;
    @Resource
    FieldService fieldService;
    @Resource
    FieldSurfaceService fieldSurfaceService;
    @Resource
    MagicService magicService;
    @Resource
    MagicTypeService magicTypeService;
    @Resource
    PartService partService;
    @Resource
    PlayerService playerService;
    @Resource
    SkillService skillService;
    @Resource
    SkillTipService skillTipService;

    @Test
    public void 实战模拟_egMax() {//e.g.
        //region 模拟数据
        System.out.println("--------------------Start--------------------");
        //1.加载球技
        Skill skill = skillService.listAll().get(0);
        List<SkillTip> skillTips = skillTipService.listAll();

        //2.加载场地-图层(可选)
        FieldLayer fieldLayer = fieldLayerService.listAll().get(0);
        Field field = fieldService.listAll().get(0);
        List<FieldSurface> fieldSurfaces = fieldSurfaceService.listAll();

        //3.加载玩家实例(绑定4)
        List<Player> players = playerService.listAll();
        //Player player = playerService.listAll().get(0);

        //4.加载角色及其技能
        //MagicType magicType=MagicType.builder().code("A03").build();
        //List<MagicType> magicTypes = magicTypeService.list(magicType);

        //Magic magic=Magic.builder().typeId("3").build();
        Magic magic = Magic.builder().build();
        List<Magic> magics = magicService.list(magic);

        Part part = partService.listAll().get(0);

        //5.公式解析器
        /*ExpressRunner runner = new ExpressRunner(true, false);
        QLExpressUtil.autoFunctionsBind(runner, FormulaEnum.MovingPoint);*/

        //region 7.对局设置
        boolean out = false;
        int count = 0;
        int opposite;

        //游戏玩家实例
        List<PlayerInstance> teams = new ArrayList<>();

        for (int i = 0; i < players.size(); i++) {
            Player player =  players.get(i);
            PlayerInstance instance = new PlayerInstance();
            BeanUtil.copyProperties(player, instance);
            instance.setMagics(magics);
            instance.setHp(Double.valueOf(instance.getAge()*100));
            instance.setFieldSide(i%2 == 0?SysConstant.field_side:2);
            instance.setPart(part);
            teams.add(instance);
        }

        Game 新对局 = Game.builder()
                .gameFormat(SysConstant.game_format)//SysConstant.game_format;2
                .teams(teams)

                .field(field)
                .fieldLayer(fieldLayer)
                .fieldSurfaces(fieldSurfaces)
                .build();

        新对局.init();

        for (int i = 0; i < teams.size(); i++) {
            PlayerInstance instance =  teams.get(i);
            initPlayerStart2(instance);
        }

        //endregion
        //endregion

        //region 循环直到(出界|没接到)
        System.out.println("--------------------Deal--------------------");
        //3.飞行计算
        do {
            System.out.println(String.format("---回合数:%s---", ++count));
            for (int i = 0; i < teams.size(); i++) {
                PlayerInstance instance = teams.get(i);

                PlayerInstance 对手 = teams.stream()
                        .filter(entry -> !entry.getFieldSide().equals(instance.getFieldSide())).findFirst().orElse(null);

                //region 双方交互
                //跑动和中场拦截的时间结果
                instance.setHp((instance.getHp() - 30) < 0 ? 0 : instance.getHp() - 30);

                BigDecimal T总 = 新对局.pursuitMeeting(对手, instance);

                if(T总.compareTo(BigDecimal.ZERO)==-1){
                    return;
                }
                Coordinate coordinate = instance.calculateFinalPosition(T总);
                //Coordinate coordinate = instance.calculateFinalPosition(对手.calculateRunTime());
                //Coordinate coordinate = instance.calculateFinalPosition(new BigDecimal(60));

                对手.setStand(coordinate);
                double hp = (对手.getHp() - 50) < 0 ? 0 : 对手.getHp() - 50;
                对手.setHp(hp);
                //endregion

                //region 判断落点
                if (instance.getFieldSide() == SysConstant.field_side) {
                    opposite = 2;
                } else {
                    opposite = SysConstant.field_side;
                }

                System.out.println(String.format("%s[%s]击球落在[%s]", instance.getFieldSide().equals(SysConstant.field_side) ? "左" : "右", instance.getName(), coordinate));

                out = 新对局.out(coordinate, opposite);

                if (out) {
                    break;
                } else {
                    新对局.isPointInRectangle(coordinate, opposite);
                }
                //endregion
            }
        } while (out == false);
        //endregion

        //region 数据展示
        System.out.println("--------------------Done--------------------");
        //endregion
    }

    /**
     * 初始站位,球速和加速度
     * @author  zgn
     * @date    2024/3/5 0005
     * @param	instance
     */
    @SneakyThrows
    private void initPlayerStart2(PlayerInstance instance) {
        //zgnTodo 依据(人|场地)变动
        Magic magicBlue = instance.getMagics().stream()
                .filter(e -> instance.getFieldSide().equals(SysConstant.field_side)
                        ?e.getCode().equals("A003"):e.getCode().equals("A004")) // Vijay, Vinod
                .findFirst() //Vijay
                .orElse(null);

        DefaultContext<String, Object> 蓝方站位数据 = new DefaultContext();
        //写法2 需要magicCode添加return
        Map<String, Object> resultBlue = (Map<String, Object>) instance.getRunner().execute(magicBlue.getMagicCode(), 蓝方站位数据, null, true, false);

        //1.人_初始点位
        Coordinate start = (Coordinate) resultBlue.get("start");//中间点位
        //2.羽毛球_速度向量
        BigDecimal V = calSpeed(instance);
        Coordinate speed = velocityDecomposition((String) resultBlue.get("speedVector"), V,instance.getRunner());

        //acceleration1:除了重力方向
        //Coordinate acceleration = new Coordinate("0,0,-0.00098");
        //acceleration2:初始化空气阻力
        BigDecimal acceleration数值 = calAcceleration(V, instance.getRunner());
        Coordinate acceleration空气阻力 = velocityDecomposition((String) resultBlue.get("speedVector"), acceleration数值,instance.getRunner());
        Coordinate acceleration = new Coordinate("0,0,-0.00098").move(acceleration空气阻力);//-0.98

        instance.setStand(start);
        instance.setSpeed(speed);
        instance.setAcceleration(acceleration);
    }

    Coordinate velocityDecomposition(String speed, BigDecimal V, ExpressRunner runner) {
        DefaultContext<String, Object> context = new DefaultContext();

        context.put("speed", new Coordinate(speed));
        context.put("V", V);

        Coordinate execute = (Coordinate) QLExpressUtil.execute(FormulaEnum.VelocityDecomposition, context, runner);
        System.out.println(String.format("速度大小:%s,速度向量:%s", V,execute));
        return execute;

    }

    BigDecimal calAcceleration(BigDecimal V, ExpressRunner runner) {
        DefaultContext<String, Object> context = new DefaultContext();
        context.put("C", SysConstant.dragCoefficient);
        context.put("P", SysConstant.density);
        context.put("S", SysConstant.area);
        context.put("V", V);
        context.put("M", SysConstant.mass);

        BigDecimal execute = (BigDecimal) QLExpressUtil.execute(FormulaEnum.AirResistanceCalculator, context, runner);

        return execute;
    }

    BigDecimal calSpeed(PlayerInstance instance) {
        DefaultContext<String, Object> context = new DefaultContext();
        context.put("instance", instance);

        BigDecimal execute = (BigDecimal) QLExpressUtil.execute(FormulaEnum.convertHandStrengthToSpeed, context, instance.getRunner());

        return execute;
    }


}
